from flask import current_app, g, request
from flask_restful import Resource, abort, marshal, fields, inputs
from flask_restful.reqparse import RequestParser

from cache import constants
from models.news import Article, Attitude, Collection
from cache.user import UserProfileCache, UserFollowingCache, UserArticleAttitudeCache, UserArticleCollectionsCache, \
    UserReadingHistoryStorage, UserReadingHistoryStorage, UserFansCache
from cache.article import ArticleDetailCache
from toutiao.utils.decorators import loginrequired
from models.user import Relation, User
from toutiao import db

import time

article_fields = {
    'art_id': fields.Integer(attribute='id'),
    'title': fields.String(attribute='title'),
    'pubdate': fields.DateTime(attribute='ctime', dt_format='iso8601'),
    'content': fields.String(attribute='content.content'),
    'aut_id': fields.Integer(attribute='user_id'),
    'ch_id': fields.Integer(attribute='channel_id'),
}


# 展示文章详情页
class DetailResource(Resource):
    """展示文章详情页"""

    def get(self, article_id):

        # 根据文章id获取文章对象
        # article = None
        # try:
        #     article = Article.query.filter(Article.id == article_id,
        #                                    Article.status == Article.STATUS.APPROVED).first()
        # except Exception as e:
        #     current_app.logger.error(e)
        #     abort(404)
        # # 把文章对象转换成字典
        # article_dict = marshal(article, article_fields)
        #
        # # 追加作者信息
        # # 获取用户对象，根据文章关联的user_id
        # user = UserProfileCache(article_dict.get('aut_id')).get()
        # # 追加作者信息
        # article_dict['aut_name'] = user['name']
        # article_dict['aut_photo'] = user['photo']

        article_dict = ArticleDetailCache(article_id).get()

        # 初始化页面展示
        # 判断是否关注
        is_followed = False
        # 判断是否喜欢
        attitude = None
        # 判断是否收藏
        is_collected = False

        # 登陆用户，展示登陆用户文章的状态
        if g.user_id:
            attitude_dict = UserArticleAttitudeCache(g.user_id).get_all()
            attitude = attitude_dict.get(int(article_id))
            # 判断是否收藏
            is_collected = UserArticleCollectionsCache(g.user_id).user_collect_target(int(article_id))
            # 判断是否关注
            is_followed = UserFollowingCache(g.user_id).user_follows_target(article_dict.get('aut_id'))

            # 添加阅读历史
            UserReadingHistoryStorage(g.user_id).save(article_id)

        article_dict['is_followed'] = is_followed
        article_dict['attitude'] = attitude
        article_dict['is_collected'] = is_collected

        # 返回响应
        return article_dict


# 用户关注
class FollowResource(Resource):
    """用户关注"""

    method_decorators = [loginrequired]

    def post(self):

        # 接受参数
        # 用户id
        user_id = g.user_id

        # 检验参数,关注的作者id
        parse = RequestParser()
        parse.add_argument('target', location='json', required=True)
        args = parse.parse_args()
        target = args.get('target')

        # 保存到数据库
        # 确定关注的作者是否存在
        user = None
        try:
            user = User.query.get(target)
        except Exception as e:
            current_app.logger.error(e)

        if not user:
            abort(404)

        # 保存到数据库
        relation = Relation()
        relation.user_id = user_id
        relation.target_user_id = target
        relation.relation = Relation.RELATION.FOLLOW
        try:
            db.session.add(relation)
            db.session.commit()
        except Exception as e:
            current_app.logger.error(e)
            db.session.rollback()  # 不加回滚会报错
            Relation.query.filter(Relation.user_id == g.user_id,
                                  Relation.target_user_id == target).update({'relation': Relation.RELATION.FOLLOW})
            db.session.commit()

        # 缓存
        time1 = time.time()  # 时间戳当权重
        UserFollowingCache(user_id).update(target, time1, 1)

        # 响应结果
        return {"target": target}

    def get(self):
        """获取用户关注列表"""

        # 接收，校验参数
        parser = RequestParser()
        parser.add_argument('page', location='args', required=False, type=inputs.positive)
        parser.add_argument('per_page', location='args', required=False, type=inputs.int_range(5, 10, 'per_page'))
        args = parser.parse_args()

        page = args.get('page') if args.get('page') is not None else 1
        per_page = args.get('per_page') if args.get('per_page') is not None else 5

        # 查询所有关注
        # followers = Relation.query.filter_by(user_id=g.user_id, relation=Relation.RELATION.FOLLOW)\
        #     .order_by(Relation.utime.desc()).all()
        #
        # # 关注总数
        # total_count = len(followers)
        #
        # # 获取关注的作者id
        # follower_ids = []
        # for follower in followers:
        #     follower_ids.append(follower.target_user_id)

        follower_ids = UserFollowingCache(g.user_id).get()
        total_count = len(follower_ids)

        # 分页
        page_followings = follower_ids[(page-1)*per_page:page*per_page]

        # 查询我的所有粉丝
        fans = UserFansCache(g.user_id).get()

        # 从用户缓存中查询作者信息
        results = []
        for follower_user_id in page_followings:
            user = UserProfileCache(follower_user_id).get()

            results.append({
                'id': follower_user_id,
                'name': user.get('name'),
                'photo': user.get('photo'),
                'mutual_follow': user.get('id') in fans  # 如果我关注人的在我的粉丝里边，就是互相关注
            })

        # 响应结果
        return {'total_count': total_count, 'page': page, 'per_page': per_page, 'results': results}


# 删除关注
class FollowDeleteResource(Resource):
    """删除关注"""

    method_decorators = [loginrequired]

    def delete(self, target):

        # 用户user_id
        user_id = g.user_id

        # 把数据库对应的关注状态修改为取消关注　０
        Relation.query.filter(Relation.user_id == user_id,
                              Relation.target_user_id == target,
                              Relation.relation == Relation.RELATION.FOLLOW).update({'relation': Relation.RELATION.DELETE})

        db.session.commit()

        # 删除缓存
        UserFollowingCache(user_id).update(target, time.time(), 0)

        return {'massage': 'OK'}


# 文章点赞
class ArticleLikeResource(Resource):
    """文章点赞"""

    method_decorators = [loginrequired]

    def post(self):
        # 接受用户id
        user_id = g.user_id

        # 接收，检验文章id
        parser = RequestParser()
        parser.add_argument('target', location='json', required=True, type=inputs.positive)
        args = parser.parse_args()
        article_id = args.get('target')

        # 查询此用户对于此文章是否有过态度
        atti = Attitude.query.filter(Attitude.user_id == user_id,
                                     Attitude.article_id == article_id).first()
        if atti is None:
            # 如果没有，新增
            atti = Attitude(
                user_id=user_id,
                article_id=article_id,
                attitude=Attitude.ATTITUDE.LIKING
            )
            db.session.add(atti)
        else:
            # 如果有，修改态度值
            atti.attitude = Attitude.ATTITUDE.LIKING

        db.session.commit()

        # 清楚缓存
        # UserArticleAttitudeCache(user_id).clear()

        # 更新缓存
        UserArticleAttitudeCache(user_id).update_field(article_id, Attitude.ATTITUDE.LIKING)

        # 响应结果
        return {'target': article_id}, 201


# 文章取消点赞
class ArticleLikeDeleteResource(Resource):
    """文章取消点赞"""

    method_decorators = [loginrequired]

    def delete(self, target):

        # 查询数据库，把点赞更新点赞状态
        Attitude.query.filter(
            Attitude.user_id == g.user_id,
            Attitude.article_id == target,
            Attitude.attitude == Attitude.ATTITUDE.LIKING
        ).update({'attitude': Attitude.ATTITUDE.DISLIKE})

        db.session.commit()

        # 清楚缓存
        # UserArticleAttitudeCache(g.user_id).clear()

        # 更新缓存
        UserArticleAttitudeCache(g.user_id).update_field(target, Attitude.ATTITUDE.DISLIKE)

        return {'massage': 'OK'}, 204


# 文章选择不喜欢
class DislikeResource(Resource):
    """文章选择不喜欢"""

    method_decorators = [loginrequired]

    def post(self):

        user_id = g.user_id

        # 接收参数，校验参数
        article_id = request.json.get('target')

        # 查询此用户对此文章是否有态度
        atti = Attitude.query.filter_by(user_id=user_id, article_id=article_id).first()

        # 判断atti是否存在
        if atti is None:
            # 不存在则新增
            atti = Attitude()
            atti.user_id = user_id
            atti.article_id = article_id
            atti.attitude = Attitude.ATTITUDE.DISLIKE

            db.session.add(atti)

        else:
            # 如果存在，则修改态度
            atti.attitude = Attitude.ATTITUDE.DISLIKE

        db.session.commit()

        # 清楚缓存
        # UserArticleAttitudeCache(user_id).clear()

        # 更新缓存
        UserArticleAttitudeCache(user_id).update_field(article_id, Attitude.ATTITUDE.DISLIKE)

        return {'target': article_id}, 201


# 取消不喜欢
class DisLikeDeleteResource(Resource):
    """取消不喜欢"""

    method_decorators = [loginrequired]

    def delete(self, target):

        user_id = g.user_id

        # 修改文章态度
        Attitude.query.filter_by(user_id=user_id, article_id=target,
                                 attitude=Attitude.ATTITUDE.DISLIKE).update({'attitude': None})

        db.session.commit()

        # 清除缓存
        UserArticleAttitudeCache(user_id).clear()

        # 更新缓存，　redis不能保存none
        # UserArticleAttitudeCache(user_id).update_field(target, None)

        return {'target': target}, 204


# 收藏文章
class CollectionResource(Resource):
    """收藏文章"""

    method_decorators = [loginrequired]

    def post(self):
        # 接收，校验参数
        parser = RequestParser()
        parser.add_argument('target', location='json', required=True, type=inputs.positive)
        args = parser.parse_args()
        article_id = args.get('target')

        # 保存数据库,如果不存在则新增，如果存在则更新is_deleted,要不然会出现Duplicate（重复）
        try:
            collection = Collection(user_id=g.user_id, article_id=article_id, is_deleted=False)
            db.session.add(collection)
            db.session.commit()
        except Exception as e:
            current_app.logger.error(e)
            db.session.rollback()
            Collection.query.filter_by(user_id=g.user_id, article_id=article_id, is_deleted=True).update({'is_deleted': False})
            db.session.commit()

        # 清除缓存
        UserArticleCollectionsCache(g.user_id).clear()

        # 响应结果
        return {'target': article_id}, 201

    def get(self):
        """获取收藏列表"""
        # 接收，校验参数
        parser = RequestParser()
        parser.add_argument('page', location='args', required=False, type=inputs.positive)
        parser.add_argument('per_page', location='args', required=False, type=inputs.int_range(
            constants.DEFAULT_ARTICLE_PER_PAGE_MIN, constants.DEFAULT_ARTICLE_PER_PAGE_MAX, 'per_page'))
        args = parser.parse_args()
        page = args.get('page') if args.get('page') is not None else 1
        per_page = args.get('per_page') if args.get('per_page') is not None else 5

        # try:
        #     page = int(page)
        #     per_page = int(per_page)
        # except Exception:
        #     page = 1
        #     per_page = 5

        # # 获取所有文章id
        # collections = Collection.query.filter(Collection.user_id == g.user_id,
        #                                       Collection.is_deleted == False).order_by(Collection.ctime.desc()).all()
        # # 文章总数
        # total_count = len(collections)
        # # 获取所有文章id
        # collection_ids = []
        # for constant in collections:
        #     collection_ids.append(constant.article_id)
        #
        # # 截取每页文章id
        # per_article_ids = collection_ids[(page-1)*per_page:page*per_page]

        # 从缓存获取数据
        total_count, per_article_ids = UserArticleCollectionsCache(g.user_id).get_page(page, per_page)

        # 根据文章id查询对应文章信息
        results = []

        for article_id in per_article_ids:
            article = ArticleDetailCache(article_id).get()
            # 判断是否点赞
            attitude_dict = UserArticleAttitudeCache(g.user_id).get_all()
            attitude = attitude_dict.get(int(article_id))
            article['is_liking'] = attitude
            results.append(article)

        # 响应结果
        return {'total_count': total_count, 'page': page, 'per_page': per_page, 'results': results}


# 取消收藏文章
class CollectionDeleteResource(Resource):
    """取消收藏文章"""

    method_decorators = [loginrequired]

    def delete(self, target):

        # 查询数据库，把is_delete修改为true
        Collection.query.filter(Collection.user_id == g.user_id,
                                Collection.article_id == target,
                                Collection.is_deleted == False).update({'is_deleted': True})
        db.session.commit()

        # 清除缓存
        UserArticleCollectionsCache(g.user_id).clear()

        return {'message': 'OK'}, 204


# 展示阅读历史
class ReadingHistoryResource(Resource):
    """展示阅读历史"""

    def get(self):
        # 接收，校验参数
        parser = RequestParser()
        parser.add_argument('page', type=inputs.positive, required=False, location='args')
        parser.add_argument('per_page', type=inputs.int_range(constants.DEFAULT_ARTICLE_PER_PAGE_MIN,
                                                                 constants.DEFAULT_ARTICLE_PER_PAGE_MAX,
                                                                 'per_page', ), required=False, location='args')

        args = parser.parse_args()
        page = 1 if args.page is None else args.page
        per_page = args.per_page if args.per_page else 5

        user_id = g.user_id

        # 从缓存中获取阅读历史, article_ids = [b'12', b'11']
        total_count, article_ids = UserReadingHistoryStorage(user_id).get(page, per_page)

        results = []

        for article_id in article_ids:
            article = ArticleDetailCache(int(article_id)).get()

            attitude_dict = UserArticleAttitudeCache(g.user_id).get_all()
            attitude = attitude_dict.get(int(article_id))

            article['is_liking'] = attitude

            results.append(article)

        # 响应结果
        return {'total_count': total_count, 'page': page, 'per_page': per_page, 'results': results}


# 粉丝列表展示
class FansResource(Resource):
    """粉丝列表展示"""
    method_decorators = [loginrequired]

    def get(self):
        # 接收，检验参数
        parser = RequestParser()
        parser.add_argument('page', location='args', required=False, type=inputs.positive)
        parser.add_argument('per_page', location='args', required=False, type=inputs.int_range(5, 10, 'per_page'))
        args = parser.parse_args()

        page = args.get('page') if args.get('page') is not None else 1
        per_page = args.get('per_page') if args.get('per_page') is not None else 5

        # 查询所有粉丝，即关注用户的id等于登陆用户的id
        # followers = Relation.query.filter(Relation.target_user_id == g.user_id,
        #                                   Relation.relation == Relation.RELATION.FOLLOW).order_by(Relation.utime.desc()).all()
        #
        # total_count = len(followers)
        #
        # # 获取这些用户的id
        # follower_ids = [follower.user_id for follower in followers]

        follower_ids = UserFansCache(g.user_id).get()
        total_count = len(follower_ids)

        # 分页
        page_follower_ids = follower_ids[(page-1)*per_page:page*per_page]
        # 查询这些用户的信息
        results = []
        for user_id in page_follower_ids:
            user = UserProfileCache(user_id).get()
            # 查询这个用户我是否关注，关注了就是互相关注
            mutual_follow = UserFollowingCache(g.user_id).user_follows_target(user.get('id'))
            results.append({
                'id': user_id,
                'name': user.get('name'),
                'photo': user.get('photo'),
                'mutual_follow': mutual_follow
            })

        # 响应结果
        return {'total_count': total_count, 'page': page, 'per_page': per_page, 'results': results}






